﻿using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using Liekhus.Testing.BDD.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TechTalk.SpecFlow;
using SpecFlowAlias = TechTalk.SpecFlow;
using System;
using System.Security;

namespace Liekhus.Testing.BDD.DevExpress
{
    //[Binding]
    public class StepDefinition : BaseStepDefinitions
    {
        private const string FUNCTIONAL_FILENAME = "FunctionalTests.ets";

        private string WorkingFolder
        {
            get
            {
                return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            }
        }

        private string TestFilePath
        {
            get
            {
                return Path.Combine(WorkingFolder, FUNCTIONAL_FILENAME);
            }
        }

        protected void WriteFileCommand(string command)
        {
            string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            Stream stream = new FileStream(TestFilePath, FileMode.Append, FileAccess.Write);
            TextWriter writer = new StreamWriter(stream);
            writer.WriteLine(command);
            writer.Close();
        }

        [Given(@"I am starting a new test")]
        public void GivenIAmStartingANewTest()
        {
            if (File.Exists(TestFilePath)) { File.Delete(TestFilePath); }
        }

        [When(@"the testing environment is reset")]
        public void WhenTheTestingEnvironmentIsReset()
        {
            string databaseName = ConfigurationManager.AppSettings["DatabaseName"];
            WriteFileCommand(string.Format("#DropDB {0}", databaseName));
            WriteFileCommand(string.Format("#RestoreDB {0}", databaseName));
        }

        [Given(@"the application is open")]
        public void GivenTheApplicationIsOpen()
        {
            string applicationName = ConfigurationManager.AppSettings["ApplicationName"];
            WriteFileCommand(string.Format("#Application {0}", applicationName));
        }

        [When("I open the record matching \"(.*)\" equals \"(.*)\"")]
        public void WhenIOpenTheRecordMatching(string fieldName, string value)
        {
            WriteFileCommand("*ProcessRecord");
            WriteFileCommand(string.Format(" {0} = {1}", fieldName, value));
        }

        public override void GivenIAmLoggedInAs(string username)
        {
            WriteFileCommand("*FillForm");
            try
            {
                WriteFileCommand(string.Format(" User Name = {0}", ConfigurationManager.AppSettings[string.Format("Login.{0}.Username", username)]));
                WriteFileCommand(string.Format(" Password = {0}", ConfigurationManager.AppSettings[string.Format("Login.{0}.Password", username)]));
            }
            catch
            {
                Assert.Fail(string.Format("Security settings for {0} have not been configured.", username));
            }
            WriteFileCommand("*Action Log On");
        }

        public override void WhenIAmAtTheScreen(string page)
        {
            WriteFileCommand(string.Format("*Action Navigation({0})", page));
        }

        public override void WhenIClickTheLink(string text)
        {
            //var link = WebBrowser.Current.Link(Find.ByText(text));

            //if (link.Exists == false)
            //{
            //    Assert.Fail(string.Format("Could not find {0} link on the page.", text));
            //}
            //link.Click();
        }

        public override void WhenIClickTheButton(string text)
        {
            string[] parts = text.Split(new char[] { ':' });

            if (parts.Length <= 1)
            {
                WriteFileCommand(string.Format("*Action {0}", text));
            }
            else
            {
                WriteFileCommand(string.Format("*Action {0}({1})", parts[0], parts[1]));
            }
        }

        public override void WhenIEnterTheFollowingInformation(SpecFlowAlias.Table table)
        {

            WriteFileCommand("*FillForm");
            foreach (var row in table.Rows)
            {
                if (!string.IsNullOrEmpty(row["Value"].ToString()))
                {
                    WriteFileCommand(string.Format(" {0} = {1}", row["Field"], row["Value"]));
                }
            }
        }

        public override void ThenIShouldSeeTheFollowingResults(SpecFlowAlias.Table table)
        {
            WriteFileCommand("*CheckFieldValues");
            foreach (var row in table.Rows)
            {
                if (!string.IsNullOrEmpty(row["Value"].ToString()))
                {
                    WriteFileCommand(string.Format(" {0} = {1}", row["Field"], row["Value"]));
                }
            }
        }

        //[Then("I should see the following on the screen")]
        public override void ThenIShouldSeeTheFollowingOnScreen(SpecFlowAlias.Table table)
        {
            //foreach (var row in table.Rows)
            //{
            //    var value = row["Value"];
            //    Assert.IsTrue(WebBrowser.Current.ContainsText(value), string.Format("Could not find text '{0}' on the page.", value));
            //}
        }

        [Then("I verify results")]
        public void WhenIVerifyResults()
        {
            ThenIVerifyResults(string.Empty);
        }

        private SecureString MakeSecureString(string text)
        {
            SecureString secure = new SecureString();
            if (string.IsNullOrEmpty(text) == false)
            {
                foreach (char c in text)
                {
                    secure.AppendChar(c);
                }
            }
            return secure;
        }

        [Then("I verify results as \"(.*)\"")]
        public void ThenIVerifyResults(string user)
        {
            string testRunner = ConfigurationManager.AppSettings["TestRunner"];
            string filePath = Path.Combine(WorkingFolder, "TestsLog.xml");
            if (File.Exists(filePath)) { File.Delete(filePath); }

            ProcessStartInfo info = new ProcessStartInfo();

            info.FileName = Path.Combine(WorkingFolder, testRunner);
            info.Arguments = TestFilePath;
            info.WindowStyle = ProcessWindowStyle.Normal;
            info.WorkingDirectory = WorkingFolder;

            if (!string.IsNullOrEmpty(user))
            {
                string login = ConfigurationManager.AppSettings[string.Format("Login.{0}.Username", user)];
                string password = ConfigurationManager.AppSettings[string.Format("Login.{0}.Password", user)];
                string domain = ConfigurationManager.AppSettings[string.Format("Login.{0}.Domain", user)];

                info.RedirectStandardError = true;
                info.RedirectStandardOutput = true;

                info.UseShellExecute = false;
                info.Domain = domain; 
                info.UserName = login;
                info.Password = MakeSecureString(password);
                info.LoadUserProfile = true;
            }

            Process p = Process.Start(info);
            p.EnableRaisingEvents = true;
            p.WaitForExit();

            bool hasPassed = false;
            if (File.Exists(filePath))
            {
                hasPassed = true;

                DataSet xml = new DataSet();
                xml.ReadXml(filePath, XmlReadMode.InferSchema);

                DataTable tests = xml.Tables["Test"];
                foreach (DataRow row in tests.Rows)
                {
                    if (!row["Result"].ToString().Equals("Passed"))
                    {
                        hasPassed = false;
                        break;
                    }
                }

                xml = null;
                if (!hasPassed)
                {
                    File.Copy(filePath, Path.Combine(WorkingFolder, string.Format("TestsLog_{0}.xml", DateTime.Now.ToString("yyMMdd_hhmm"))));
                }
                File.Delete(filePath);
            }
            else
            {
                Assert.Fail(string.Format("Results file {0} does not exist.", filePath));
            }

            Assert.IsTrue(hasPassed == true);
        }

    }
}